#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
测试身份证号码和手机号码生成器
"""

import sys
import os

# 添加项目路径
sys.path.insert(0, os.path.dirname(__file__))

from utils.data.id_generator import IDGenerator

def test_generate_id_number():
    """测试身份证号码生成"""
    print("测试身份证号码生成:")
    
    # 测试随机生成身份证号码
    id_number = IDGenerator.generate_id_number()
    print(f"随机生成的身份证号码: {id_number}")
    assert len(id_number) == 18, f"身份证号码应该是18位，实际是{len(id_number)}位"
    
    # 测试指定2位前缀生成身份证号码
    id_number = IDGenerator.generate_id_number(prefix="11")
    print(f"指定2位前缀生成的身份证号码: {id_number}")
    assert id_number.startswith("11"), "身份证号码应该以11开头"
    assert len(id_number) == 18, f"身份证号码应该是18位，实际是{len(id_number)}位"
    
    # 测试指定6位前缀生成身份证号码
    id_number = IDGenerator.generate_id_number(prefix="110105")
    print(f"指定6位前缀生成的身份证号码: {id_number}")
    assert id_number.startswith("110105"), "身份证号码应该以110105开头"
    assert len(id_number) == 18, f"身份证号码应该是18位，实际是{len(id_number)}位"
    
    # 测试指定年龄范围生成身份证号码
    id_number = IDGenerator.generate_id_number(age_range=[20, 30])
    print(f"指定年龄范围[20, 30]生成的身份证号码: {id_number}")
    assert len(id_number) == 18, f"身份证号码应该是18位，实际是{len(id_number)}位"
    
    # 测试年龄判断功能
    from datetime import datetime
    birth_year = int(id_number[6:10])
    current_year = datetime.now().year
    age = current_year - birth_year
    assert 20 <= age <= 30, f"生成的身份证号码年龄应该在20-30岁之间，实际为{age}岁"
    
    # 测试带多条件的身份证号码生成（基于MD5加密后的完整数字）
    # 使用负数索引表示倒数位置
    try:
        conditions = [
            {
                "positions": [-2, -1],  # MD5后数字的倒数第2位和倒数第1位
                "range": [10, 99]       # 范围在10-99之间
            },
            {
                "positions": [10, 14],  # MD5后数字的第10-14位
                "range": [10000, 99999] # 范围在10000-99999之间
            }
        ]
        id_number = IDGenerator.generate_id_number(digit_conditions=conditions)
        print(f"满足多条件的身份证号码: {id_number}")
        # 注意：这里我们不直接验证，因为条件是基于MD5加密后的完整数字
    except RuntimeError as e:
        print(f"生成满足条件的身份证号码时遇到错误: {e}")
    
    # 测试同时指定前缀、年龄范围和条件
    try:
        conditions = [
            {
                "positions": [-1, -2],    # MD5后数字的倒数第1-2位
                "range": [50, 150]      # 范围在50-150之间
            }
        ]
        id_number = IDGenerator.generate_id_number(
            prefix="31", 
            age_range=[25, 35],
            digit_conditions=conditions
        )
        print(f"同时指定前缀、年龄范围和条件生成的身份证号码: {id_number}")
    except RuntimeError as e:
        print(f"生成满足所有条件的身份证号码时遇到错误: {e}")
    
    # 测试超出范围的位置条件（应该会作废该条件）
    try:
        conditions = [
            {
                "positions": [1000, 2000],  # 超出MD5数字长度的位置
                "range": [1, 10]            # 范围
            }
        ]
        # 这种情况下应该很难生成满足条件的号码，会抛出异常
        id_number = IDGenerator.generate_id_number(digit_conditions=conditions, max_attempts=100)
        print(f"使用超出范围位置条件生成的身份证号码: {id_number}")
    except RuntimeError as e:
        print(f"使用超出范围位置条件时遇到错误: {e}")
    
    # 测试完整重新生成功能
    try:
        # 使用不可能满足的条件来测试完整重试机制
        impossible_conditions = [
            {
                "positions": [0, 1],  # 第1-2位
                "range": [999, 1000]  # 不可能的范围
            }
        ]
        # 应该会尝试max_attempts次后重新生成一个普通号码
        id_number = IDGenerator.generate_id_number(digit_conditions=impossible_conditions, max_attempts=10)
        print(f"无法满足条件时重新生成的身份证号码: {id_number}")
        # 验证仍然生成了一个有效的18位身份证号码
        assert len(id_number) == 18, f"重新生成的身份证号码应该是18位，实际是{len(id_number)}位"
    except RuntimeError as e:
        print(f"完整重新生成功能测试遇到错误: {e}")
    
    print("身份证号码生成测试通过!")

def test_generate_mobile_number():
    """测试手机号码生成"""
    print("\n测试手机号码生成:")
    
    # 测试随机生成手机号码
    mobile_number = IDGenerator.generate_mobile_number()
    print(f"随机生成的手机号码: {mobile_number}")
    assert len(mobile_number) == 11, f"手机号码应该是11位，实际是{len(mobile_number)}位"
    
    # 测试指定3位前缀生成手机号码
    mobile_number = IDGenerator.generate_mobile_number(prefix="138")
    print(f"指定3位前缀生成的手机号码: {mobile_number}")
    assert mobile_number.startswith("138"), "手机号码应该以138开头"
    assert len(mobile_number) == 11, f"手机号码应该是11位，实际是{len(mobile_number)}位"
    
    # 测试指定6位前缀生成手机号码
    mobile_number = IDGenerator.generate_mobile_number(prefix="138123")
    print(f"指定6位前缀生成的手机号码: {mobile_number}")
    assert mobile_number.startswith("138123"), "手机号码应该以138123开头"
    assert len(mobile_number) == 11, f"手机号码应该是11位，实际是{len(mobile_number)}位"
    
    # 测试带条件的手机号码生成（基于MD5加密后的完整数字）
    try:
        conditions = [
            {
                "positions": [-1, -2],  # MD5后数字的倒数第1位和倒数第2位
                "range": [10, 50]     # 范围在10-50之间
            }
        ]
        mobile_number = IDGenerator.generate_mobile_number(digit_conditions=conditions)
        print(f"满足条件的手机号码: {mobile_number}")
        # 注意：这里我们不直接验证，因为条件是基于MD5加密后的完整数字
    except RuntimeError as e:
        print(f"生成满足条件的手机号码时遇到错误: {e}")
    
    print("手机号码生成测试通过!")

def test_generate_transaction_number():
    """测试交易流水号生成"""
    print("\n测试交易流水号生成:")
    
    # 测试生成交易流水号
    transaction_numbers = set()
    for i in range(10):
        transaction_number = IDGenerator.generate_transaction_number("TX")
        transaction_numbers.add(transaction_number)
        print(f"生成的交易流水号 {i+1}: {transaction_number}")
    
    # 验证生成的流水号都是唯一的
    assert len(transaction_numbers) == 10, "生成的交易流水号应该都是唯一的"
    
    # 测试多线程环境下生成的唯一性
    import threading
    import time
    
    results = []
    lock = threading.Lock()
    
    def generate_numbers():
        numbers = []
        for _ in range(5):
            number = IDGenerator.generate_transaction_number("MT")
            numbers.append(number)
            time.sleep(0.001)  # 短暂休眠以增加并发可能性
        with lock:
            results.extend(numbers)
    
    # 创建并启动多个线程
    threads = []
    for i in range(3):
        thread = threading.Thread(target=generate_numbers)
        threads.append(thread)
        thread.start()
    
    # 等待所有线程完成
    for thread in threads:
        thread.join()
    
    # 验证所有生成的流水号都是唯一的
    unique_numbers = set(results)
    print(f"\n多线程测试生成了 {len(results)} 个流水号，其中唯一的是 {len(unique_numbers)} 个")
    assert len(unique_numbers) == len(results), "多线程环境下生成的交易流水号应该都是唯一的"
    
    print("交易流水号生成测试通过!")

if __name__ == "__main__":
    test_generate_id_number()
    test_generate_mobile_number()
    test_generate_transaction_number()